#include "nokia_5110.h"

#ifdef __cplusplus
 extern "C" {
#endif

//This table contains the hex values that represent pixels
//for a font that is 5 pixels wide and 8 pixels high
static const uint8_t ASCII[][FONT_6x8] = {
  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },// sp
  { 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 },// !
  { 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 },// "
  { 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 },// #
  { 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 },// $
  { 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 },// %
  { 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 },// &
  { 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 },// '
  { 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 },// (
  { 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 },// )
  { 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 },// *
  { 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 },// +
  { 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 },// ,
  { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 },// -
  { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 },// .
  { 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 },// /
  { 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E },// 0
  { 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 },// 1
  { 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 },// 2
  { 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 },// 3
  { 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 },// 4
  { 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 },// 5
  { 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 },// 6
  { 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 },// 7
  { 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 },// 8
  { 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E },// 9
  { 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 },// :
  { 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 },// ;
  { 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 },// <
  { 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 },// =
  { 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 },// >
  { 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 },// ?
  { 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E },// @
  { 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C },// A
  { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 },// B
  { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 },// C
  { 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C },// D
  { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 },// E
  { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 },// F
  { 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A },// G
  { 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F },// H
  { 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 },// I
  { 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 },// J
  { 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 },// K
  { 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 },// L
  { 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F },// M
  { 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F },// N
  { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E },// O
  { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 },// P
  { 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E },// Q
  { 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 },// R
  { 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 },// S
  { 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 },// T
  { 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F },// U
  { 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F },// V
  { 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F },// W
  { 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 },// X
  { 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 },// Y
  { 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 },// Z
  { 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 },// [
  { 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 },// 55
  { 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 },// ]
  { 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 },// ^
  { 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 },// _
  { 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 },// '
  { 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 },// a
  { 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 },// b
  { 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 },// c
  { 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F },// d
  { 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 },// e
  { 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 },// f
  { 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C },// g
  { 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 },// h
  { 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 },// i
  { 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 },// j
  { 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 },// k
  { 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 },// l
  { 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 },// m
  { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 },// n
  { 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 },// o
  { 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 },// p
  { 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC },// q
  { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 },// r
  { 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 },// s
  { 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 },// t
  { 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C },// u
  { 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C },// v
  { 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C },// w
  { 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 },// x
  { 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C },// y
  { 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 },// z
  { 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 }// horiz lines
}; 

void Delay_LCD5110(uint16_t u16Delay)
{
  uint16_t i=0;
  for(i = 0; i < u16Delay; i++);
}

/**************************************/
ErrorStatus Write_SPI(uint8_t u8Data)
{  
  uint16_t u16Data = 0x00FF & (uint8_t)u8Data;
  
  while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_BSY) == SET);
  GPIO_ResetBits(GPIOx,PIN_SCE);
  
  while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
  SPI_I2S_SendData(SPIx, u16Data);
  
  while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_BSY) == SET);
  GPIO_SetBits(GPIOx,PIN_SCE);
  
  return SUCCESS;
}

/**************************************/
void InitPerphChip_LCD5110(void)
{
  /* initialization for SPIx */
  SPI_InitTypeDef  SPI_InitStructure;
  
  RCC_APBnPeriphClockCmd(RCC_APBnPeriph_SPIx,ENABLE);
  
  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  
  SPI_Init(SPIx, &SPI_InitStructure);
  
  /* initialization for GPIO */
  GPIO_InitTypeDef  GPIO_InitStructure;
  /* GPIOD Periph clock enable */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx, ENABLE);

  /* Configure PD12, PD13, PD14 and PD15 in output pushpull mode */
  GPIO_InitStructure.GPIO_Pin = PIN_RES | PIN_SCE | PIN_DC;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOx, &GPIO_InitStructure);
  
  GPIO_InitStructure.GPIO_Pin = PIN_SDIN | PIN_SCLK;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Init(GPIOx, &GPIO_InitStructure);
  
  /* ALT mode */
  GPIO_PinAFConfig(GPIOx, GPIO_PinSource_SCLK, GPIO_AF_SPIx);
  GPIO_PinAFConfig(GPIOx, GPIO_PinSource_SDIN, GPIO_AF_SPIx);
  
  /* enable SPI */  
  SPI_Cmd(SPIx, ENABLE);
  
}

/**************************************/
/* parameter: u8Vop = 3.3 */
void Init_LCD5110(uint8_t u8Vop)
{
  InitPerphChip_LCD5110();
  
  GPIO_ResetBits(GPIOx,PIN_SCE);
  GPIO_ResetBits(GPIOx,PIN_RES);
  Delay_LCD5110(TIME_OUT);
  GPIO_SetBits(GPIOx,PIN_RES);
  /* PD = 0; V = 0; H = 1 */
  WriteCommand_LCD5110(MASK_FUNCTION_SET | MASK_BIT_H); /* 0x21 */
  /* set Vop for LCD */
  WriteCommand_LCD5110(SET_VOP_3_3V); /* 0x84*/
  /* PD = 0; V = 0; H = 0 */
  WriteCommand_LCD5110(MASK_FUNCTION_SET); /* 0x20 */
  /* set display into NORMAL mode */
  WriteCommand_LCD5110(DISPLAY_NORMAL_MODE); /* 0x0C */
}

/**************************************/
void SetMode_LCD5110(uint8_t u8Mode)
{
  Enable_LCD5110(ENABLE_LCD5110);
  if (u8Mode == MODE_COMMAND_LCD_5110)
  {
    /* clear pin D/C */
    GPIO_ResetBits(GPIOx,PIN_DC);
  }
  else
  {
    /* set pin D/C */
    GPIO_SetBits(GPIOx,PIN_DC);
  }
}

/**************************************/
void Enable_LCD5110(uint8_t u8Enable)
{
  if (ENABLE_LCD5110 == u8Enable)
  {
    GPIO_ResetBits(GPIOx,PIN_SCE);
  }
  else
  {
    GPIO_SetBits(GPIOx,PIN_SCE);
  }
}

/**************************************/
/*
*              (0,0) ------> X
*                    |
*                    |
*                    Y
*/
ErrorStatus SetPosition_LCD5110(uint8_t u8Position_X, uint8_t u8Position_Y)
{
  ErrorStatus temp = SUCCESS;
  
  if (SUCCESS != WriteCommand_LCD5110(MASK_POS_X(u8Position_X)))
    temp = ERROR;
  if (SUCCESS != WriteCommand_LCD5110(MASK_POS_Y(u8Position_Y)))
    temp = ERROR;
  return temp;
}

/**************************************/
ErrorStatus WriteCommand_LCD5110(uint8_t u8Command)
{
  SetMode_LCD5110(MODE_COMMAND_LCD_5110);
  return Write_SPI(u8Command);
}

/**************************************/
ErrorStatus WriteData_LCD5110(uint8_t u8Data)
{
  ErrorStatus temp = SUCCESS;  
  /* transmit data to RAM's display */
  SetMode_LCD5110(MODE_DATA_LCD_5110);
  if (SUCCESS != Write_SPI(u8Data))
    temp = ERROR;
  return temp;
}

/**************************************/
void PrintFont5x8(uint8_t character)
{
  uint8_t i;
  uint8_t temp_character = character - OFFSET_START_FONT;
  for (i = 0; i < FONT_6x8; i++)
  {
    WriteData_LCD5110(ASCII[temp_character][i]);
    Delay_LCD5110(TIME_OUT);
  }
}

void PrintString_LCD5110(uint8_t *Str)
{
  while(*Str)
  {
    PrintFont5x8(*Str);
    Str++;
  }
}

/**************************************/
void clean_screen(void)
{
  uint8_t x,y;
  for(x = 0; x < 6; x++)
    for(y=0; y < 84; y++)
      WriteData_LCD5110(0);
}


/******************************************************************************/
/*
*       paramater :     u8Number - value display on LCD 5110
*                       u8LengthDisplay - length display
*/
ErrorStatus DisplayNumber(uint8_t u8Number, uint8_t u8LengthDisplay)
{
  uint8_t u8DonVi;
  uint8_t u8Chuc;
  uint8_t u8Tram = 1;
  uint8_t u8Temp = u8Number;
  
  if ((3 < u8LengthDisplay) || (1 > u8LengthDisplay))
  {
    return ERROR;
  }
  
  if (2 < u8LengthDisplay)
  {
    u8Tram = u8Temp / 100;
    u8Temp = u8Temp % 100;
    if (0 != u8Tram)
      PrintFont5x8(u8Tram+48);
    else
      PrintFont5x8(' ');
  }
  if (1 < u8LengthDisplay)
  {
    u8Chuc = u8Temp / 10;
    u8Temp = u8Temp % 10;
    if ((0 == u8Tram) || (0 == u8Chuc))
      PrintFont5x8(' ');
    else
      PrintFont5x8(u8Chuc+48);
  }
  if (0 < u8LengthDisplay)
  {
    u8DonVi = u8Temp;
    PrintFont5x8(u8DonVi+48); 
  }
  
  return SUCCESS;
}


#ifdef __cplusplus
}
#endif
